__author__ = 'x0r'

import os
import re
from datetime import timedelta
from socket import getfqdn
import socket
import json
import httplib2
from urllib import urlencode
from settings import Settings
import verifymodule
import commands

from sysdiskspace import SysDiskSpace
from mondata import MonData


# Poller class.
# Retrieves system information

class Poller:
    def __init__(self):
        """
        Default constructor
        """
        self.__conf = Settings ("magentd.conf")
        self.__remoteHost = self.__conf.value["remoteHost"]
        self.__remotePort = self.__conf.value["remotePort"]
        self.__agentID = self.__conf.value["agentID"]
        self.__sysID = verifymodule.verify ()
        self.__mon_res = {}

    def getSysUptime(self,args):
        """
        Get system uptime.
        Reads from /proc/uptime

        """
        with open('/proc/uptime', 'r') as f:
            uptime_seconds = float(f.readline().split()[0])
            uptime_string = str(timedelta(seconds=uptime_seconds))
        return uptime_string

    def getSysLoadAvg(self,args):
        """
        Get system load average
        0.01 0.20 0.50
        """
        return re.sub('\(|\)', '', str(os.getloadavg()))

    def getHostname(self,args):
        """
        Get host fqdn
        """
        return str(getfqdn())

    def getMountPointsList(self):
        mount = commands.getoutput('mount -v')
        lines = mount.split('\n')
        points = map(lambda line: line.split()[2], lines)
        return points

    def getFsStats(self, mountpoint='/'):
        """
        Get file system free_space/total_space
        Units: megabytes (1024 kbytes)
        @param mountpoint
        Default mount point for statvfs.
        """
        try:
            fs = os.statvfs(mountpoint)
            self.total_size = (fs.f_blocks * fs.f_bsize) / (1024 * 1024)
            self.free_space = (fs.f_bfree * fs.f_bsize) / (1024 * 1024)
            self.used_space = self.total_size-self.free_space
        except OSError:
            pass
        finally:
            return int(self.total_size), int(self.used_space), \
                   int(self.free_space)

    def getSysDiskSpace(self,args):
        print ("DEBUG (getSysDiskSpace): %s" % args)
        if len(args)==0: # return all partitions
            mp = self.getMountPointsList()
            objects=[]      #array of SysDiskSpace objects
            for point in mp:
                sys=SysDiskSpace(point)
                sys.Total,sys.Used,sys.Free = self.getFsStats(point)
                # Filter out zero(virtual) partitions
                if sys.Total==0:
                    continue
                #   print (sys.Total, sys.Free)
                objects.append(sys.__dict__)
                #   print objects
            del sys
            return objects
        else:
            #return only selected partitions
            objects=[]
            for point in args:
                sys=SysDiskSpace(point)
                sys.Total,sys.Used,sys.Free = self.getFsStats(point)
                if sys.Total == 0:
                    continue
                objects.append(sys.__dict__)
        del sys
        return objects

    # This dict is used to map monitored parameters to functions that return desired metrics.
    # In order to add additional functionality, one should add new mapping here.
    func_map = {
        'SysHostname': getHostname,
        'SysLoadAvg' : getSysLoadAvg,
        'SysDiskSpc' : getSysDiskSpace,
        'SysUptime'  : getSysUptime
    }

    def cfor(self,first,test,update):
        """
        C-style for loop
        """
        while test(first):
            yield first
            first = update(first)

    def ProcessRequest(self, req):
        """
        Invoke functions from func_map according to the input.
        Result is put into objects dynamic attributes.
        """
        self.__data = req
        myMonData=MonData()
        array_size=len(self.__data)
        for i in self.cfor(0,lambda i:i<array_size,lambda i:i+1):
            setattr(myMonData,self.__data[i]["Name"],self.func_map[str(self.__data[i]["Name"])](self,self.__data[i]["Args"]))

        post_data = json.dumps(myMonData.__dict__,indent=True)
        print "About to send: "+post_data
        try:
            conn = httplib2.Http(timeout=3)
            resp, content = conn.request("http://"+self.__remoteHost+"/data?agentID="+self.__agentID+"&sysID="+self.__sysID,"GET",post_data)
            print "Data sent\n"
            print "Server responded: %s %s" % (resp.status,content)
            del myMonData
        except socket.timeout:
            print "Error: Timeout reached while connecting to server"
        except socket.error as ex:
            print "Error: %s" % ex.strerror
        except httplib2.ServerNotFoundError as err:
            print "Error: %s" % err.message
        print "Proccessing data: ", self.__data


